package com.example.javafx.bilibilidownload.util;

import com.example.javafx.bilibilidownload.constant.BiliVideoEnum;
import com.example.javafx.bilibilidownload.constant.VideoConstant;
import com.example.javafx.bilibilidownload.pojo.BiliFavoriteSimplePojo;
import com.example.javafx.bilibilidownload.pojo.BiliFocusPojo;
import com.example.javafx.bilibilidownload.pojo.BiliUpPojo;
import com.example.javafx.bilibilidownload.pojo.BiliVideoPojo;
import com.example.javafx.bilibilidownload.pojo.VideoDownloadResult;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

import lombok.val;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.TrueFileFilter;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zengbang
 * @create 2024-08-09 13:53
 **/
public class BiliFileUtil {

    private static final Logger log = LogManager.getLogger(BiliFileUtil.class);


    public static ObjectMapper objectMapper = new ObjectMapper();

    static {
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
    }

    public static int biliDefaultPageSize = 20;

    /**
     * 爬取up主页失败视频信息
     */
    public static String biliUpSpaceErrorFile = "spaceErrorList";

    public static String biliUpUnionVideoDir = "union";

    public static String biliUpVideoDir = "video";

    /**
     * 爬取收藏夹失败视频信息
     */
    public static String biliFavoriteErrorFile = "favoriteErrorList";

    public static String biliFavoriteVideoDir = "favorite";

    /**
     * 爬取集合失败视频信息
     */
    public static String biliColletionErrorFile = "collectionErrorList";

    public static String biliColletionVideoDir = "collection";

    public static String biliSingleVideoDir = "single";

    public static String biliSingleErrorFile = "singleErrorList";
    public static String biliVideoIsUnion = "1";

    public static String biliDownloadErrorDir = "downloadError";

    public static String biliMainDir = "bilifile";

    public static String biliUpSpaceFile = "spaceDetail";

    public static String biliFocusDir = "focus";

    public static String FS = File.separator;

    public static boolean checkFileExist(String fileName) {
        return new File(VideoConstant.absolutePath + fileName).exists();
    }

    public static File getAbsoluteFile(String fileName) {
        return new File(VideoConstant.absolutePath + fileName);
    }

    /**
     * @Description: 获取up视频解析后文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getFocusUpFile(String focusName, String upName) {
        return getFocusDir() + FS + focusName + FS + fileNameReplaceInvalidCharater(upName) + ".txt";
    }

    public static String getFocusFile(String focusName) {
        return getFocusDir() + FS + focusName + ".txt";
    }

    public static String getFocusDir() {
        if (!checkFileExist(biliMainDir + FS + biliFocusDir)) {
            getAbsoluteFile(biliMainDir + FS + biliFocusDir).mkdir();
        }
        return biliMainDir + FS + biliFocusDir;
    }


    public static String getSingledir() {
        return biliMainDir + FS + biliSingleVideoDir;
    }

    public static String getSingleVideoFile(String collectionName, String videoTitle) {
        String fileName = "";
        if (StringUtils.isEmpty(collectionName)) {
            fileName = getSingledir() + FS + fileNameReplaceInvalidCharater(videoTitle);
        } else {
            fileName = getSingledir() + FS + collectionName + FS + fileNameReplaceInvalidCharater(videoTitle);
        }
        return fileName;
    }

    public static String getSingleErrorFile() {
        return getSingledir() + FS + biliSingleErrorFile;
    }

    /**
     * @Description: 获取视频下载文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getSingleVideoDownloadFile(String videoName) {
        return VideoConstant.getTempPath() + FS + videoName;
    }

    /**
     * @Description: 获取音频下载文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getSingleAudioDownloadFile(String audioName) {
        return VideoConstant.getTempPath() + FS + audioName;
    }

    /**
     * @Description: 获取完整成品的文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getSingleCompleteConvertFile(String collectionName, String fileName) {
//        if (StringUtils.isEmpty(collectionName)) {
//            return VideoConstant.getTargetPath() + FS + biliSingleVideoDir + FS + fileName;
//        } else {
        return VideoConstant.getTargetPath() + FS + biliSingleVideoDir + FS + collectionName + FS + fileName;
//        }
    }

    /**
     * @Description: 获取下载出错日志文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getSingleDownloadErrorFile(String title) {
        return VideoConstant.getTargetPath() + FS + biliSingleVideoDir + FS + biliDownloadErrorDir + FS + title + ".txt";
    }


    /**
     * @Description: 获取up视频解析后文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getUpVideoFile(String unionVideo, String upName, String author, String videoTitle) {
        String fileName = "";
        // 如果不是联合视频的话，直接放在up下面的video文件下
        if (!biliVideoIsUnion.equals(unionVideo)) {
            fileName = biliMainDir + FS + author + FS + biliUpVideoDir + FS + fileNameReplaceInvalidCharater(videoTitle) + ".txt";
        } else {
            // 联合视频的话，还是放在up下面的union文件下
            fileName = biliMainDir + FS + upName + FS + biliUpVideoDir + FS + biliUpUnionVideoDir + FS + author + FS + fileNameReplaceInvalidCharater(videoTitle) + ".txt";
        }
        return fileName;
    }

    /**
     * @Description: 获取up详情文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getUpSpaceFile(String upName) {
        return biliMainDir + FS + upName + FS + biliUpSpaceFile;
    }

    /**
     * @Description: 获取爬取up视频出错日志文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getUpSpaceErrorFile(String upName) {
        return biliMainDir + FS + upName + FS + biliUpSpaceErrorFile;
    }


    /**
     * @Description: 获取下载出错日志文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getUpDownloadErrorFile(String upName, String title) {
        return VideoConstant.getTargetPath() + FS + upName + FS + biliDownloadErrorDir + FS + title + ".txt";
    }


    /**
     * @Description: 获取视频下载文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getUpVideoDownloadFile(String unionVideo, String upName, String videoName) {
        String videoPath = "";
        if (!biliVideoIsUnion.equals(unionVideo)) {
            videoPath = VideoConstant.getTempPath() + FS + videoName;
        } else {
            // 联合视频的话，还是放在up下面的union文件下
            videoPath = VideoConstant.getTempPath() + FS + videoName;
        }
        return videoPath;
    }

    /**
     * @Description: 获取音频下载文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getUpAudioDownloadFile(String unionVideo, String upName, String audioName) {
        String videoPath = "";
        if (!biliVideoIsUnion.equals(unionVideo)) {
            videoPath = VideoConstant.getTempPath() + FS + audioName;
        } else {
            // 联合视频的话，还是放在up下面的union文件下
            videoPath = VideoConstant.getTempPath() + FS + audioName;
        }
        return videoPath;
    }

    /**
     * @Description: 获取完整成品的文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getUpCompleteConvertFile(String unionVideo, String upName, String author, String fileName) {
        String conpleteConvertFile = "";
        if (!biliVideoIsUnion.equals(unionVideo)) {
            conpleteConvertFile = VideoConstant.getTargetPath() + FS + author + FS + fileName;
        } else {
            // 联合视频的话，还是放在up下面的union文件下
            conpleteConvertFile = VideoConstant.getTargetPath() + FS + upName + FS + biliUpUnionVideoDir + FS + author + FS + fileName;
        }
        return conpleteConvertFile;
    }

    /**
     * @Description: 获取视频下载文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getFavoriteVideoDownloadFile(String videoName) {
        return VideoConstant.getTempPath() + FS + biliFavoriteVideoDir + FS + videoName;
    }

    /**
     * @Description: 获取音频下载文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getFavoriteAudioDownloadFile(String audioName) {
        return VideoConstant.getTempPath() + FS + biliFavoriteVideoDir + FS + audioName;
    }

    /**
     * @Description: 获取完整成品的文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getFavoriteCompleteConvertFile(String favoriteName, String fileName) {
        return VideoConstant.getTargetPath() + FS + biliFavoriteVideoDir + FS + favoriteName + FS + fileName;

    }

    /**
     * @Description: 获取爬取up视频出错日志文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getFavoriteErrorFile() {
        return getFavoritedir() + FS + biliFavoriteErrorFile;
    }

    /**
     * @Description: 获取下载出错日志文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getFavoriteDownloadErrorFile(String title) {
        return VideoConstant.getTargetPath() + FS + biliFavoriteVideoDir + FS + biliDownloadErrorDir + FS + title + ".txt";
    }

    /**
     * @Description: 获取收藏视频解析后文件路径
     * @Author: bangbang23333
     * @Date: 2024/8/12 16:33
     */
    public static String getFavoriteVideoFile(String favoriteName, String videoTitle) {
//        String fileName = BilibiliConstant.biliMainDir + FS + biliFavoriteVideoDir + FS
//                + author + FS + fileNameReplaceInvalidCharater(videoTitle);
        // 添加了作者名字，反而不认识了，没有必要
        String fileName = biliMainDir + FS + biliFavoriteVideoDir + FS + favoriteName + FS + fileNameReplaceInvalidCharater(videoTitle);
        return fileName;
    }

    public static String getFavoritedir() {
        return biliMainDir + FS + biliFavoriteVideoDir;
    }

    public static String getFavoriteFile(String fileName) {
        return getFavoritedir() + FS + fileName;
    }

    public static String getFavoriteFileDir(String favoritaName) {
        return getFavoritedir() + FS + favoritaName;
    }


    public static <T> Boolean writeInfo(String fileName, T content) {
        try {
            // 如果 fileName 不是 txt 结尾，则加上
            if (!StringUtils.endsWithIgnoreCase(fileName, ".txt")) {
                fileName = fileName + ".txt";
            }
            File file = getAbsoluteFile(fileName);
            if (!file.exists()) FileUtils.touch(file);
            // 如果是错误文件，则追加写入
            if (StringUtils.containsIgnoreCase(fileName, "error")) {
                FileUtils.writeStringToFile(getAbsoluteFile(fileName), content.toString(), StandardCharsets.UTF_8, true);
                FileUtils.writeStringToFile(getAbsoluteFile(fileName), "\n=========================", StandardCharsets.UTF_8, true);
            } else {
                // 否则直接覆盖写入
                objectMapper.writeValue(file, content);
            }
            return true;
        } catch (Exception e) {
            log.error("写入文件失败, 文件名字是:{}", fileName, e);
            return false;
        }
    }

    public static <T> T readInfo(File file, Class T) {
        try {
            if (!StringUtils.containsIgnoreCase(file.getPath(), "error")) {
                T result = (T) objectMapper.readValue(file, T);
                return result;
            }
            return null;
        } catch (Exception e) {
            log.error("读取文件失败, 文件名字是:{}", file.getPath(), e);
            return null;
        }
    }

    public static boolean isNotExistAndNeedWriteDown(String fileName, Object pojo) {
        // 如果之前已经读取过了该视频信息就不读取了
        if (checkFileExist(fileName)) {
            // 打印日志，提示跳过该文件
            log.debug("文件已创建, 跳过创建该文件:{}", fileName);
            return false;
        } else {
            //写入该文件
            log.info("文件未创建, 创建该文件:{}", fileName);
            BiliFileUtil.writeInfo(fileName, pojo);
            return true;
        }
    }

    public static List<File> getFileListByPath(String path, List<String> excludeStr) {
        // 添加绝对路径
        path = VideoConstant.absolutePath + path;
        List<File> files = new ArrayList<>();
        File file = new File(path);
        if (file.exists()) {
            files = FileUtils.listFiles(file, new IOFileFilter() {
                @Override
                public boolean accept(File file) {
                    // 如果是隐藏文件，则跳过
                    if (file.getName().startsWith(".")) {
                        return false;
                    }
                    if (null != excludeStr && excludeStr.stream().anyMatch(str -> !file.getPath().contains(str))) {
                        return false;
                    }
                    return true;
                }

                @Override
                public boolean accept(File dir, String name) {
                    return true;
                }
            }, TrueFileFilter.INSTANCE).stream().collect(Collectors.toList());
        }
        return files;
    }

    public static List<File> getFileListByPath(String path) {
        return getFileListByPath(path, new ArrayList<>());
    }

    public static String fileNameReplaceInvalidCharater(String name) {
        if (null == name) return name;
        return name.replace("／", "-").replace("/", "").replace("\\", "").replace("?", "").replace("|", "").replace("*", "").replace("\"", "").replace(",", "").replace(":", "").replace("<", "").replace(">", "");
    }

    public static VideoDownloadResult getResult(BiliVideoEnum biliVideoEnum, BiliVideoPojo bilibiliVideo, String upName) {
        String completedVideoPath = "";
        String videoPath = "";
        String audioPath = "";
        String downloadErrorInfoPath = "";
        // 如果是up视频
        if (biliVideoEnum.isUp()) {
            completedVideoPath = BiliFileUtil.getUpCompleteConvertFile(bilibiliVideo.getIs_union_video(), upName, bilibiliVideo.getAuthor(), bilibiliVideo.getVideoName());
            videoPath = BiliFileUtil.getUpVideoDownloadFile(bilibiliVideo.getIs_union_video(), upName, bilibiliVideo.getVideoName());
            audioPath = BiliFileUtil.getUpAudioDownloadFile(bilibiliVideo.getIs_union_video(), upName, bilibiliVideo.getAudioName());
            downloadErrorInfoPath = getUpDownloadErrorFile(upName, bilibiliVideo.getTitle());
        }
        // 如果是收藏视频
        if (biliVideoEnum.isFavorite()) {
            // 成品视频区分普通视频还是合集视频
            if (StringUtils.isEmpty(bilibiliVideo.getCollectionName())) {
                completedVideoPath = BiliFileUtil.getFavoriteCompleteConvertFile(bilibiliVideo.getFavoriteName(),
                        bilibiliVideo.getVideoName());
            } else {
                completedVideoPath =
                        BiliFileUtil.getFavoriteCompleteConvertFile(bilibiliVideo.getFavoriteName() + FS + bilibiliVideo.getCollectionName(),
                                bilibiliVideo.getVideoName());
            }
            videoPath = BiliFileUtil.getFavoriteVideoDownloadFile(bilibiliVideo.getVideoName());
            audioPath = BiliFileUtil.getFavoriteAudioDownloadFile(bilibiliVideo.getAudioName());
            downloadErrorInfoPath = getFavoriteDownloadErrorFile(bilibiliVideo.getTitle());
        }
        // 如果是单个视频
        if (biliVideoEnum.isSingle()) {
            completedVideoPath = BiliFileUtil.getSingleCompleteConvertFile(bilibiliVideo.getCollectionName(), bilibiliVideo.getVideoName());
            videoPath = BiliFileUtil.getSingleVideoDownloadFile(bilibiliVideo.getVideoName());
            audioPath = BiliFileUtil.getSingleAudioDownloadFile(bilibiliVideo.getAudioName());
            downloadErrorInfoPath = getSingleDownloadErrorFile(bilibiliVideo.getTitle());
        }
        VideoDownloadResult videoDownloadResult = new VideoDownloadResult(completedVideoPath, videoPath, audioPath, downloadErrorInfoPath);
        return videoDownloadResult;
    }

    public static String getDirectorySize(File directory) {
        if (!directory.exists()) {
            return "0";
        }
        return FileUtils.byteCountToDisplaySize(FileUtils.sizeOfDirectory(directory));
    }

    public static long getDirectoryLongSize(File directory) {
        if (!directory.exists()) {
            return 0L;
        }
        return FileUtils.sizeOfDirectory(directory);
    }

    public static String getUpDownloadVideoSize(BiliUpPojo biliUpPojo) {
        return getDirectorySize(getUpDownloadDir(biliUpPojo.getUpName()));
    }

    public static String getFavoriteDownloadVideoSize(BiliFavoriteSimplePojo biliFavoriteSimplePojo) {
        return getDirectorySize(getAbsoluteFile(VideoConstant.getTargetPath() + FS + "favorite" + FS + biliFavoriteSimplePojo.getTitle()));
    }

    public static File getUpDownloadDir(String upName) {
        return getAbsoluteFile(VideoConstant.getTargetPath() + FS + upName);
    }

    public static String getVideoDownloadFileSize(BiliVideoPojo value) {
        VideoDownloadResult result = BiliFileUtil.getResult(BiliVideoEnum.Up, value, value.getAuthor());
        if (!getAbsoluteFile(result.completedVideoPath).exists()) {
            return "0";
        }
        return FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(getAbsoluteFile(result.completedVideoPath)));
    }
}
